#ifndef PROBLEMA_H_
#define PROBLEMA_H_
#include<iostream>

//ErrorJudgment函数用于判断所找的点是否近似于零点,若是则返回true值.
bool ErrorJudgment(double f_x, double eps){
    if(f_x < eps && f_x > -eps) return true;
    else return false;
}

//CheckPrint函数用于检查用户所给函数在所求零点附近区域上是否连续并输出结果.若不连续,则所找到的点可能并不是零点,需要手动判断连续性.
void CheckPrint(double x, double (*f)(double)){
    if(ErrorJudgment(f(x), 1))
        std::cout << "此函数有近似零点" << x << std::endl;
    else
        std::cout << x << "可能不是此函数的近似零点!" << std::endl;
}

//创建基类EquationSolver及其公共成员纯虚函数solve
class EquationSolver
{
public:
    virtual double solve() = 0;
};

//派生类一:二分法
class Bisection : public EquationSolver
{
private:
    double left, right;
    double epsilon;
    double (*fun)(double);

public:  
    Bisection(double a, double b, double eps, double (*f)(double)){
        left = a;
        right = b;
        epsilon = eps;
        fun = f;
    }
    double solve(){
        if(ErrorJudgment(fun(left) , epsilon)) return left;
        if(ErrorJudgment(fun(right) , epsilon)) return right;//判断初始点是否接近零点
        double mid = (left + right)/2;
        while(!(ErrorJudgment(fun(mid) , epsilon)) && !(ErrorJudgment((right-left)/2 , epsilon))){
            if(fun(left) * fun(mid) < 0){
                right = mid;
            }
            else{
                left = mid;
            }
            mid = (left + right)/2;
        } 
        return mid;
    }

};

//派生类二:牛顿法
class Newton : public EquationSolver
{
private:
    double initial_pt;
    double epsilon;
    double (*fun)(double);
    double (*dfun)(double);
public:
    Newton(double x_0, double eps, double (*f)(double), double (*df)(double)){
        initial_pt = x_0;
        epsilon = eps;
        fun = f;
        dfun = df;
    }
    double solve(){
        if(ErrorJudgment(fun(initial_pt) , epsilon)) return initial_pt;//判断初始点是否接近零点
        double new_pt = initial_pt - fun(initial_pt)/dfun(initial_pt);
        while(!(ErrorJudgment(fun(new_pt) , epsilon)) && !(ErrorJudgment(new_pt-initial_pt , epsilon))){
            double t = new_pt - fun(new_pt)/dfun(new_pt);
            initial_pt = new_pt;
            new_pt = t;
        }
        return new_pt;
    }

};

//派生类三:割线法
class Secant : public EquationSolver
{
private:
    double initial_pt1, initial_pt2;
    double epsilon;
    double (*fun)(double);
public:
    Secant(double x_0, double x_1, double eps, double (*f)(double)){
        initial_pt1 = x_0;
        initial_pt2 = x_1;
        epsilon = eps;
        fun = f;
    }
    double solve(){
        if(ErrorJudgment(fun(initial_pt1) , epsilon)) return initial_pt1;
        if(ErrorJudgment(fun(initial_pt2) , epsilon)) return initial_pt2;//判断初始点是否接近零点
        double new_pt = initial_pt2 - fun(initial_pt2) * (initial_pt2-initial_pt1) / (fun(initial_pt2) - fun(initial_pt1));
        while(!(ErrorJudgment(fun(new_pt) , epsilon)) && !(ErrorJudgment(new_pt-initial_pt2 , epsilon))){
            double t = new_pt - fun(new_pt) * (new_pt-initial_pt2) / (fun(new_pt)-fun(initial_pt2));
            initial_pt2 = new_pt;
            new_pt = t;
        }
        return new_pt;
    }
    
};

#endif